package com.eva.shiro.service;

import com.eva.dao.system.model.SystemLoginLog;
import com.eva.framework.captcha.service.ImageCaptchaService;
import com.eva.framework.common.constants.ResponseStatus;
import com.eva.framework.common.exception.BusinessException;
import com.eva.framework.common.utils.Utils;
import com.eva.framework.config.AppConfig;
import com.eva.framework.rbac.model.RbacLoginByPasswordDTO;
import com.eva.framework.rbac.model.RbacUserInfo;
import com.eva.service.system.SystemLoginLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Slf4j
@Service
public class LoginByPasswordService {

    @Resource
    private AppConfig appConfig;

    @Resource
    private ImageCaptchaService imageCaptchaService;

    @Resource
    private SystemLoginLogService systemLoginLogService;

    /**
     * 密码登录
     *
     * @param dto 登录参数
     * @return String Token
     */
    public String login (RbacLoginByPasswordDTO dto, HttpServletRequest request) throws AuthenticationException {
        SystemLoginLog loginLog = new SystemLoginLog();
        loginLog.setLoginUsername(dto.getUsername());
        loginLog.setLoginTime(new Date());
        loginLog.setSystemVersion(appConfig.getVersion());
        loginLog.setIp(Utils.User_Client.getIP(request));
        loginLog.setLocation(Utils.Location.getLocationString(loginLog.getIp()));
        loginLog.setPlatform(Utils.User_Client.getPlatform(request));
        loginLog.setClientInfo(Utils.User_Client.getBrowser(request));
        loginLog.setOsInfo(Utils.User_Client.getOS(request));
        loginLog.setServerIp(Utils.Server.getIP());
        // 校验验证码
        try {
            imageCaptchaService.check(dto.getUuid(), dto.getCode());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            loginLog.setReason(e.getMessage().length() > 200 ? (e.getMessage().substring(0, 190) + "...") : e.getMessage());
            loginLog.setSuccess(Boolean.FALSE);
            systemLoginLogService.create(loginLog);
            throw e;
        }
        try {
            // 登录
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(dto.getUsername(), dto.getPassword());
            subject.login(token);
            RbacUserInfo userInfo = ((RbacUserInfo)subject.getPrincipal());
            // 填充登录令牌
            String sessionId = (String)subject.getSession().getId();
            userInfo.setToken(sessionId);
            // 创建登录日志
            loginLog.setUserId(userInfo.getId());
            loginLog.setSuccess(Boolean.TRUE);
            systemLoginLogService.create(loginLog);
            return userInfo.getToken();
        } catch (AuthenticationException e) {
            log.error("登录失败", e);
            loginLog.setReason(e.getMessage().length() > 200 ? (e.getMessage().substring(0, 190) + "...") : e.getMessage());
            loginLog.setSuccess(Boolean.FALSE);
            systemLoginLogService.create(loginLog);
            if (e.getCause() instanceof BusinessException) {
                throw (BusinessException) e.getCause();
            }
            throw new BusinessException(ResponseStatus.ACCOUNT_INCORRECT);
        }
    }
}
